﻿using Furion;
using FurStudy.Application;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;

namespace FurStudy.Web.Entry.Controllers
{
    [Route("api/[controller]")]
    public class DefaultController : ControllerBase
    {
        #region 读取Appsetting.json信息的两种方式

        /// <summary>
        /// 通过App.Configuration[path]读取
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public string Get()
        {
            return $@"名称：{App.Configuration["AppInfo:Name"]}，
                      版本：{App.Configuration["AppInfo:Version"]}，
                      公司：{App.Configuration["AppInfo:Company"]}";
        }

        ///// <summary>
        ///// 依赖注入IConfiguration对象读取
        ///// </summary>
        ///// <param name="configuration"></param>
        ///// <returns></returns>
        //[HttpGet]
        //public string Get([FromServices] IConfiguration configuration)
        //{
        //    return $@"名称：{configuration["AppInfo:Name"]}，
        //              版本：{configuration["AppInfo:Version"]}，
        //              公司：{configuration["AppInfo:Company"]}";
        //}

        #endregion

        #region 依赖注入的三种方式

        private readonly IConfiguration _configuration;
        private readonly AppInfoOptions options1;
        private readonly AppInfoOptions options2;
        private readonly AppInfoOptions options3;
        /// <summary>
        /// 构造函数注入方式
        /// </summary>
        /// <param name="configuration"></param>
        public DefaultController(IConfiguration configuration,
            IOptions<AppInfoOptions> options,
            IOptionsSnapshot<AppInfoOptions> optionsSnapshot,
            IOptionsMonitor<AppInfoOptions> optionsMonitor)
        {
            _configuration = configuration;
            options1 = options.Value;
            options2 = optionsSnapshot.Value;
            options3 = optionsMonitor.CurrentValue;
        }

        /// <summary>
        /// 参数注入方式[FromServices]
        /// </summary>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public string GetConfiguration([FromServices] IConfiguration configuration)
        {
            return string.Empty;
        }

        /// <summary>
        /// 属性注入方式
        /// </summary>
        public IConfiguration Configuration { get; set; }

        #endregion

        #region 路径符查找节点

        public void ReadAppInfo()
        {
            // 读取第二层
            var companyName1 = App.Configuration["AppInfo:Name"]; // Furion
            // 读取第三层
            var companyName2 = App.Configuration["AppInfo:Company:Name"]; // Baiqian
            // 读取第四层
            var companyName3 = App.Configuration["AppInfo:Company:Address:Detail"]; // 中山市东区紫马公园西门
            // 读取第N层
            var companyName = App.Configuration["AppInfo:Tier2:Tier3:Tier4...Tiern1:Tiern3..."]; // => 中山市东区紫马公园西门

            // 查找数组节点
            var name = App.Configuration["array[0]"]; // 0是索引数字
        }
        #endregion

        #region 读取emailsetting.json配置

        public void ReadEmailJson()
        {
            // App.Configuration[path]
            var smtpServer = App.Configuration["outlook:smtp:server"]; // smtp.office365.com
            // 依赖注入方式
            var smtpServer2 = _configuration["outlook:smtp:server"]; // smtp.office365.com
        }

        #endregion

        #region 配置更改通知（热更新）

        public void HotUpdate()
        {
            var appInfoConfiguration = App.Configuration.GetSection("AppInfo");
            ChangeToken.OnChange(() => App.Configuration.GetReloadToken(), () =>
            {
                var name = appInfoConfiguration["Name"]; // 实时的Name最新值
                var version = appInfoConfiguration["Verison"]; // 实时的Version最新值
            });

            // [注] 如果监听全局配置文件传入App.Configuration.GetReloadToken()，如果只需要监听特定节点，传入App.Configuration.GetSection("AppInfo")
        }

        #endregion

        #region 重载配置(OverloadConfiguration)

        // Furion 会在应用启动的时候对 IConfiguration 进行静态缓存，如果使用了 App.Configuration 静态属性且配置数据已发生变更，则调用以下方法刷新即可
        // App.Configuration.Reload();

        #endregion

        #region 读取AppInfoOptions信息

        /// <summary>
        /// 通过 App.GetOptions<TOptions>(path) 读取
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public string GetAppInfoOptions()
        {
            // // 不推荐采用此方式读取，该方式仅在 ConfigureServices 启动时使用
            var appInfo = App.GetConfig<AppInfoOptions>("AppInfo", true);
            return $@"名称：{appInfo.Name}，
                      版本：{appInfo.Version}，
                      公司：{appInfo.Company}";
        }

        /// <summary>
        /// 依赖注入方式
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public string GetAppInfoOptionsByInject()
        {
            var info1 = $@"名称：{options1.Name}，
                      版本：{options1.Version}，
                      公司：{options1.Company}";

            var info2 = $@"名称：{options2.Name}，
                      版本：{options2.Version}，
                      公司：{options2.Company}";

            var info3 = $@"名称：{options3.Name}，
                      版本：{options3.Version}，
                      公司：{options3.Company}";

            return $"{info1}-{info2}-{info3}";
        }

        /// <summary>
        /// App.GetOptions<TOptions>()
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public string GetAppInfoOptionsByTOptions()
        {
            var opt1 = App.GetOptions<AppInfoOptions>();
            var info1 = $@"名称：{opt1.Name}，
                      版本：{opt1.Version}，
                      公司：{opt1.Company}";

            var opt2 = App.GetOptions<AppInfoOptions>();
            var info2 = $@"名称：{opt2.Name}，
                      版本：{opt2.Version}，
                      公司：{opt2.Company}";

            var opt3 = App.GetOptions<AppInfoOptions>();
            var info3 = $@"名称：{opt3.Name}，
                      版本：{opt3.Version}，
                      公司：{opt3.Company}";

            return $"{info1}-{info2}-{info3}";
        }

        // 如何选择读取方式
        // ·如果选项需要在多个地方使用，则无论任何时候都不推荐使用 App.GetOptions<TOptions>(path)
        // ·在可依赖注入类中，依赖注入 IOptions[Snapshot | Monitor]<TOptions> 读取
        // ·在静态类/非依赖注入类中，选择 App.GetOptions[Snapshot|Monitor]<TOptions>() 读取

        #endregion
    }
}
